using System;
using System.Collections.Generic;

namespace AIFSContentManagementSystem.Criteria
{
    public class Criterion : ModelBase
    {
        int? criteriaId;

        public int? CriteriaId
        {
            get { return criteriaId; }
            set { criteriaId = value; }
        }

        List<Expression> criterionExpression;
        
        public Criterion()
        {
            criterionExpression = new List<Expression>();
        }

        /// <summary>
        /// This should only be used for serialization. Do not use this for internal
        /// </summary>
        public string[] CriteriaExpressionArray
        {
            //not required. Only for XML serialization
            get
            {
                return new string[] { };
            }
            set
            {
                criterionExpression = Expression.CreateFromArray(value);
            }
        }

        /// <summary>
        /// Used by internal objects to get the strongly typed criterion expression list
        /// </summary>
        public virtual List<Expression> CriteriaExpression
        {
            get
            {
                return criterionExpression;
            }
            set
            {
                criterionExpression = value;
            }
        }

        /// <summary>
        /// Method tests whether the criteria list provided "fits" the criteria associated with this article.
        /// </summary>        
        /// <returns><c>true</c> if meets one of the criterion or <c>false</c> if does not meet any of the criteria</returns>
        public bool IsMatch(List<Criterion> CriteriaToMatch)
        {
            if (CriteriaToMatch == null || CriteriaToMatch.Count == 0)
                throw new ArgumentNullException("CriteriaToMatch can not be null or empty");

            bool assertionResult = false;
            foreach (Criterion criterionToMatch in CriteriaToMatch)
            {
                assertionResult = IsMatch(criterionToMatch);
                if (assertionResult)
                    break;
            }

            return assertionResult;
        }

        /// <summary>
        /// This method asserts the 2 series of criteria. All comparisions are AND-ed within this method
        /// </summary>
        private bool IsMatch(Criterion CriterionToMatch)
        {
            List<Expression> factExpList = this.CriteriaExpression;
            List<Expression> expectedExpList = CriterionToMatch.CriteriaExpression;


            int countMatches = 0;
            foreach (Expression expectedExp in expectedExpList)
            {
                foreach (Expression factExp in factExpList)
                {
                    if (factExp.Match(expectedExp))
                    {
                        countMatches = countMatches + 1;
                        break; //DO NOT GO FURTHER FOR THIS COMBINATION
                    }
                }
            }

            //All expected criteria matched or not
            return (countMatches == expectedExpList.Count);
        }
    }
}
